// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import "internal/bytealg"

// 错误接口标识运行时错误。
type Error interface {
	error

	// RuntimeError是一个不可操作的函数，但
	// 用于区分运行时类型
	// 错误与普通错误：如果类型具有RuntimeError方法，则该类型为
	// 运行时错误。
	RuntimeError()
}

// TypeAssertionError解释了失败的类型断言。
type TypeAssertionError struct {
	_interface    *_type
	concrete      *_type
	asserted      *_type
	missingMethod string // 接口所需的一个方法，具体
}

func (*TypeAssertionError) RuntimeError() {}

func (e *TypeAssertionError) Error() string {
	inter := "interface"
	if e._interface != nil {
		inter = e._interface.string()
	}
	as := e.asserted.string()
	if e.concrete == nil {
		return "interface conversion: " + inter + " is nil, not " + as
	}
	cs := e.concrete.string()
	if e.missingMethod == "" {
		msg := "interface conversion: " + inter + " is " + cs + ", not " + as
		if cs == as {
			// 中缺少了一个方法，提供了更清晰的错误消息
			if e.concrete.pkgpath() != e.asserted.pkgpath() {
				msg += " (types from different packages)"
			} else {
				msg += " (types from different scopes)"
			}
		}
		return msg
	}
	return "interface conversion: " + cs + " is not " + as +
		": missing method " + e.missingMethod
}

// go:nosplit 
// itoa将val转换为十进制表示。结果是
// 写入buf中的某个位置，并返回结果的位置。
// buf必须至少为20字节。
func itoa(buf []byte, val uint64) []byte {
	i := len(buf) - 1
	for val >= 10 {
		buf[i] = byte(val%10 + '0')
		i--
		val /= 10
	}
	buf[i] = byte(val + '0')
	return buf[i:]
}

// 错误字符串表示由单个字符串描述的运行时错误。
type errorString string

func (e errorString) RuntimeError() {}

func (e errorString) Error() string {
	return "runtime error: " + string(e)
}

type errorAddressString struct {
	msg  string  // 错误消息
	addr uintptr // 发生错误的内存地址
}

func (e errorAddressString) RuntimeError() {}

func (e errorAddressString) Error() string {
	return "runtime error: " + e.msg
}

// Addr返回发生错误的内存地址。
// 提供的地址是最好的。
// 结果的准确性可能取决于平台。
// 提供此方法的错误将仅作为
// 返回，这是使用runtime/debug.SetPanicOnFault的结果。
func (e errorAddressString) Addr() uintptr {
	return e.addr
}

// plainError表示调用errorString.error（）后，使用不带
// 前缀“runtime error:”的字符串描述的运行时错误。
// 见第14965期。
type plainError string

func (e plainError) RuntimeError() {}

func (e plainError) Error() string {
	return string(e)
}

// BoundersError表示索引或切片操作出错。
type boundsError struct {
	x int64
	y int
	// 索引或切片表达式中的值可以是有符号的，也可以是无符号的。这意味着我们需要65位来编码所有可能的索引，从-2^63到2^64-1。
	// 相反，我们将跟踪x应被解释为有符号还是无符号。众所周知，y是非负的，适合于整数。0<=x<len（s）failed 
	signed bool
	code   boundsErrorCode
}

type boundsErrorCode uint8

const (

	boundsSliceAlen // /s[？：x]，0<=x<=len（s）failed 

	boundsSlice3Acap // s[？：？：x]，0<=x<=cap失败的
	boundsSlice3B    // s[？：x:y]，0<=x<=y失败（但边界许可证3A没有发生）
	boundsSlice3C    // /s[x:y:？]，0<=x<=y失败（但边界许可证3A/B没有发生）

	// 注意：在上面的示例中，len和cap存储在y 
)

// BoundersErrorFmts为各种越界恐慌提供错误文本。
// 注意：如果更改这些字符串，则应在BoundersError中调整缓冲区的大小。错误如下。
var boundsErrorFmts = [...]string{
	boundsIndex:      "index out of range [%x] with length %y",
	boundsSliceAlen:  "slice bounds out of range [:%x] with length %y",
	boundsSliceAcap:  "slice bounds out of range [:%x] with capacity %y",
	boundsSliceB:     "slice bounds out of range [%x:%y]",
	boundsSlice3Alen: "slice bounds out of range [::%x] with length %y",
	boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y",
	boundsSlice3B:    "slice bounds out of range [:%x:%y]",
	boundsSlice3C:    "slice bounds out of range [%x:%y:]",
	boundsConvert:    "cannot convert slice with length %y to pointer to array with length %x",
}

// 如果x为负，则boundsNegErrorFmts是覆盖格式。在这种情况下，没有必要报告y。
var boundsNegErrorFmts = [...]string{
	boundsIndex:      "index out of range [%x]",
	boundsSliceAlen:  "slice bounds out of range [:%x]",
	boundsSliceAcap:  "slice bounds out of range [:%x]",
	boundsSliceB:     "slice bounds out of range [%x:]",
	boundsSlice3Alen: "slice bounds out of range [::%x]",
	boundsSlice3Acap: "slice bounds out of range [::%x]",
	boundsSlice3B:    "slice bounds out of range [:%x:]",
	boundsSlice3C:    "slice bounds out of range [%x::]",
}

func (e boundsError) RuntimeError() {}

func appendIntStr(b []byte, v int64, signed bool) []byte {
	if signed && v < 0 {
		b = append(b, '-')
		v = -v
	}
	var buf [20]byte
	b = append(b, itoa(buf[:], uint64(v))...)
	return b
}

func (e boundsError) Error() string {
	fmt := boundsErrorFmts[e.code]
	if e.signed && e.x < 0 {
		fmt = boundsNegErrorFmts[e.code]
	}
	// 最大消息长度为99:“运行时错误：切片超出范围[：：%x]，容量为%y”
	// x最多可包含20个字符。y最多可以是19。
	b := make([]byte, 0, 100)
	b = append(b, "runtime error: "...)
	for i := 0; i < len(fmt); i++ {
		c := fmt[i]
		if c != '%' {
			b = append(b, c)
			continue
		}
		i++
		switch fmt[i] {
		case 'x':
			b = appendIntStr(b, e.x, e.signed)
		case 'y':
			b = appendIntStr(b, int64(e.y), true)
		}
	}
	return string(b)
}

type stringer interface {
	String() string
}

// printany打印传递给panic的参数。
// 如果使用具有字符串或错误方法的值调用panic，则
// 它已被预印本转换为字符串。
func printany(i interface{}) {
	switch v := i.(type) {
	case nil:
		print("nil")
	case bool:
		print(v)
	case int:
		print(v)
	case int8:
		print(v)
	case int16:
		print(v)
	case int32:
		print(v)
	case int64:
		print(v)
	case uint:
		print(v)
	case uint8:
		print(v)
	case uint16:
		print(v)
	case uint32:
		print(v)
	case uint64:
		print(v)
	case uintptr:
		print(v)
	case float32:
		print(v)
	case float64:
		print(v)
	case complex64:
		print(v)
	case complex128:
		print(v)
	case string:
		print(v)
	default:
		printanycustomtype(i)
	}
}

func printanycustomtype(i interface{}) {
	eface := efaceOf(&i)
	typestring := eface._type.string()

	switch eface._type.kind {
	case kindString:
		print(typestring, `("`, *(*string)(eface.data), `")`)
	case kindBool:
		print(typestring, "(", *(*bool)(eface.data), ")")
	case kindInt:
		print(typestring, "(", *(*int)(eface.data), ")")
	case kindInt8:
		print(typestring, "(", *(*int8)(eface.data), ")")
	case kindInt16:
		print(typestring, "(", *(*int16)(eface.data), ")")
	case kindInt32:
		print(typestring, "(", *(*int32)(eface.data), ")")
	case kindInt64:
		print(typestring, "(", *(*int64)(eface.data), ")")
	case kindUint:
		print(typestring, "(", *(*uint)(eface.data), ")")
	case kindUint8:
		print(typestring, "(", *(*uint8)(eface.data), ")")
	case kindUint16:
		print(typestring, "(", *(*uint16)(eface.data), ")")
	case kindUint32:
		print(typestring, "(", *(*uint32)(eface.data), ")")
	case kindUint64:
		print(typestring, "(", *(*uint64)(eface.data), ")")
	case kindUintptr:
		print(typestring, "(", *(*uintptr)(eface.data), ")")
	case kindFloat32:
		print(typestring, "(", *(*float32)(eface.data), ")")
	case kindFloat64:
		print(typestring, "(", *(*float64)(eface.data), ")")
	case kindComplex64:
		print(typestring, *(*complex64)(eface.data))
	case kindComplex128:
		print(typestring, *(*complex128)(eface.data))
	default:
		print("(", typestring, ") ", eface.data)
	}
}

// panicwrap为使用nil指针接收器调用包装值方法
// 生成一个panic。
// 
// 从生成的包装器代码调用。
func panicwrap() {
	pc := getcallerpc()
	name := funcname(findfunc(pc))
	// 名称类似于“main.（*T）.F”。
	// 我们想提取pkg（“main”）、typ（“T”）和meth（“F”）。
	// 通过找到paren来完成。
	i := bytealg.IndexByteString(name, '(')
	if i < 0 {
		throw("panicwrap: no ( in " + name)
	}
	pkg := name[:i-1]
	if i+2 >= len(name) || name[i-1:i+2] != ".(*" {
		throw("panicwrap: unexpected string after package name: " + name)
	}
	name = name[i+2:]
	i = bytealg.IndexByteString(name, ')')
	if i < 0 {
		throw("panicwrap: no ) in " + name)
	}
	if i+2 >= len(name) || name[i:i+2] != ")." {
		throw("panicwrap: unexpected string after type name: " + name)
	}
	typ := name[:i]
	meth := name[i+2:]
	panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer"))
}
